﻿using System.Reflection;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace Marbles.Core.Runtime
{
    public class CodeRunner
    {

        public CodeCompileUnit GetCompileUnit(string code)
        {
            CodeNamespace rootNs = new CodeNamespace("CodeGen");
            CodeMemberMethod member = new CodeMemberMethod();
            CodeTypeDeclaration rootClass = new CodeTypeDeclaration("CodeRunner");
            CodeCompileUnit codeUnit = new CodeCompileUnit();
            codeUnit.ReferencedAssemblies.Add("System");
            codeUnit.ReferencedAssemblies.Add("Syste.Core");
            codeUnit.ReferencedAssemblies.Add("System.Data");
            codeUnit.ReferencedAssemblies.Add("System.Web");
            codeUnit.ReferencedAssemblies.Add("System.Xml");
            codeUnit.ReferencedAssemblies.Add("System.Xml.Linq");

            rootNs.Imports.Add(new CodeNamespaceImport("System"));
            rootNs.Imports.Add(new CodeNamespaceImport("System.Web"));
            rootNs.Imports.Add(new CodeNamespaceImport("System.Web.UI"));
            rootNs.Imports.Add(new CodeNamespaceImport("System.Xml"));
            rootNs.Imports.Add(new CodeNamespaceImport("System.Data"));

            member.Name = "Evaluate";
            member.ReturnType = new CodeTypeReference(typeof(object));
            member.Statements.Add(new CodeSnippetExpression(code));
            rootClass.IsClass = true;
            rootClass.Members.Add(member);
            rootNs.Types.Add(rootClass);
            codeUnit.Namespaces.Add(rootNs);
            return codeUnit;
        }

        public object Evaluate(string code, CodeDomProvider CodeDomProvider)
        {
            CompilerParameters parm = new CompilerParameters();
            CodeCompileUnit codeUnit = GetCompileUnit(code);
            CompilerResults result = null;

            parm.CompilerOptions = "/t:library";
            parm.GenerateExecutable = false;
            parm.GenerateInMemory = true;
            result = CodeDomProvider.CompileAssemblyFromDom(parm, codeUnit);

            if (result.Errors.Count > 0)
            {
                return null;
            }

            Object o = result.CompiledAssembly.CreateInstance("CodeGen.CodeRunner");
            Type t = o.GetType();
            MethodInfo mi = t.GetMethod("Evaluate");
            object returnValue = mi.Invoke(o, null);
            return returnValue;
        }

        public object EvaluateCSharp(string code)
        {
            return Evaluate(code, new Microsoft.CSharp.CSharpCodeProvider());
        }

        public object EvaluateVisualBasic(string code)
        {
            return Evaluate(code, new Microsoft.VisualBasic.VBCodeProvider());
        }
    }
}
